package com.syh.jn.scm.domain.supplier.entity.logistics;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.util.exception.IllegalParameterException;
import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.util.other.ExtStringUtils;
import cn.redscarf.commons.spring.SpringContextUtils;
import cn.redscarf.commons.util.validator.ValidationUtils;
import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import com.syh.core.ddd.domain.AbstractSimpleAggregate;
import com.syh.core.ddd.domain.CodeExpEnum;
import com.syh.core.ddd.domain.CodeGenerateUtil;
import com.syh.jn.scm.domain.supplier.entity.base.Storehouse;
import com.syh.jn.scm.domain.supplier.entity.purchase.PurchaseOrder;
import com.syh.jn.scm.domain.supplier.entity.purchase.PurchaseReturnOrder;
import com.syh.jn.scm.domain.supplier.entity.sale.SaleOrder;
import com.syh.jn.scm.domain.supplier.entity.sale.SaleOrderItem;
import com.syh.jn.scm.domain.supplier.entity.sale.SaleReturnOrder;
import com.syh.jn.scm.domain.supplier.repository.base.StorehouseReadRepository;
import com.syh.jn.scm.domain.supplier.repository.logistics.LogisticsBillReadRepository;
import com.syh.jn.scm.domain.supplier.repository.logistics.LogisticsBillRepository;
import com.syh.jn.scm.domain.supplier.repository.purchase.PurchaseOrderReadRepository;
import com.syh.jn.scm.domain.supplier.repository.purchase.PurchaseOrderRepository;
import com.syh.jn.scm.domain.supplier.repository.purchase.PurchaseReturnOrderRepository;
import com.syh.jn.scm.domain.supplier.repository.sale.SaleOrderReadRepository;
import com.syh.jn.scm.domain.supplier.repository.sale.SaleOrderRepository;
import com.syh.jn.scm.domain.supplier.repository.sale.SaleReturnOrderReadRepository;
import com.syh.jn.scm.domain.upstream.entity.logistics.UpLogisticsBill;
import com.syh.jn.scm.dto.supplier.logistics.LogisticsBillMto;
import com.syh.jn.scm.dto.supplier.logistics.LogisticsBillSto;
import com.syh.jn.scm.exception.BusinessException;
import com.syh.jn.scm.service.api.supplier.logistics.enums.LogisticsBillEnums;
import com.syh.jn.scm.service.api.supplier.purchase.enums.PurchaseOrderEnums;
import com.syh.jn.scm.service.api.supplier.purchase.enums.PurchaseReturnOrderEnums;
import com.syh.jn.scm.service.api.supplier.sale.enums.SaleOrderEnums;
import com.syh.jn.scm.service.api.supplier.sale.enums.SaleReturnOrderEnums;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 物流单
 */
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class LogisticsBill extends AbstractSimpleAggregate<Long> {
  /**
   * 物流单编号
   */
  private String code;
  /**
   * 对应订单id
   */
  private Long orderId;
  /**
   * 订单类型
   */
  private Short orderType;
  /**
   * 订单编号
   */
  private String orderCode;
  /**
   * 客户类型
   */
  private Short customerType;
  /**
   * 客户id
   */
  private Long customerId;
  /**
   * 物流状态(0：未发车 1:已发车 2：已收货)
   */
  private Short logisticsState;
  /**
   * 物流单物流结算状态(0：未生成对账单 1：已生成对账单 -1：已取消)
   */
  private Short statementState;
  /**
   * 对应物流对账单id
   */
  private Long statementId;
  /**
   * 发货仓库id
   */
  private Long depotId;
  /**
   * 物流类型(1:空运 2:陆运 3:海运)
   */
  private Short logisticsType;
  /**
   * 物流公司id
   */
  private Long logisticsCompanyId;
  /**
   * 航班号
   */
  private String flightNumber;
  /**
   * 海航号
   */
  private String shippingNumber;
  /**
   * 货车车牌号
   */
  private String plateNumber;
  /**
   * 预计到达时间(物流)
   */
  private Long etaDateTimestamp;
  /**
   * 司机姓名
   */
  private String driverName;
  /**
   * 司机联系电话
   */
  private String driverContactPhone;
  /**
   * 发货备注(物流)
   */
  private String deliveryNotes;
  /**
   * 发货地区编码
   */

  private String deliveryDeliAreaCode;
  /**
   * 发货地址省 市 区
   */
  private String deliveryDeliArea;
  /**
   * 发货人详细地址
   */
  private String deliveryDeliAddress;
  /**
   * 发货时间
   */
  private Long deliveryTimestamp;
  /**
   * 上传发货图片URL
   */
  private String deliveryCarImgUrl;
  /**
   * 上传发货图片URL
   */
  private String deliveryContractImgUrl;
  /**
   * 上传收货图片URL
   */
  private String collectContractImgUrl;
  /**
   * 运费承担方(0:买家承担  1:卖家承担费用)
   */
  private Short freightTake;
  /**
   * 运费承担方式(0:预收买家  1:买家到付)
   */
  private Short freightType;
  /**
   * 运费金额
   */
  private BigDecimal totalFreight;
  /**
   * 收货人姓名
   */
  private String deliName;
  /**
   * 收货人联系电话
   */
  private String deliTel;
  /**
   * 要求到货时间
   */
  private Long receiveTimestamp;
  /**
   * 收货地区编码
   */
  private String deliAreaCode;
  /**
   * 收货地址省 市 区
   */
  private String deliArea;
  /**
   * 收货人详细地址
   */
  private String deliAddress;
  /**
   * 入库时间(收货)
   */
  private Long storageTimestamp;
  /**
   * 归属服务商id
   */
  private Long businessEntityId;
  /**
   * 主单id
   */
  private Long subjectBillId;
  /**
   * 副单（直采直销用）
   */
  private LogisticsBill secondaryBill;
  /**
   * 发货类型(1:物流发货,2:快递发货,3:其它发货)
   */
  private Short deliveryType;
  /**
   * 快递单号
   */
  private String courierNumber;
  /**
   * items
   */
  private List<LogisticsBillItem> items;

  /**
   * 新增物流单
   *
   * @param sto
   */
  public LogisticsBill(LogisticsBillSto sto) {
    ExtAssert.notNull(sto, "对象为空");
    switch (sto.getOrderType()) {
      //销售单
      case 0:
        SaleOrderReadRepository saleOrderRead = (SaleOrderReadRepository) SpringContextUtils.getBean("saleOrderRepositoryImpl");
        SaleOrder saleOrder = saleOrderRead.getById(sto.getOrderId());
        if (saleOrder != null) {
          if (saleOrder.getGeneratedState().equals(SaleOrderEnums.GeneratedState.LOGISTICS_WHOLE_GENERATE.getStatus())) {
            throw new BusinessException("销售单" + saleOrder.getCode() + "现有物流单已满足发货数量，无法再新建物流单！");
          }
          sto.setOrderCode(saleOrder.getCode());
          sto.setCustomerType(LogisticsBillEnums.CustomerType.DOWNSTREAM.getStatus());
          sto.setCustomerId(saleOrder.getDownStreamCompanyId());
          sto.setDeliName(saleOrder.getDeliName());
          sto.setDeliTel(saleOrder.getDeliTel());
          sto.setDeliAreaCode(saleOrder.getDeliAreaCode());
          sto.setDeliArea(saleOrder.getDeliArea());
          sto.setDeliAddress(saleOrder.getDeliAddress());
          sto.setReceiveTimestamp(saleOrder.getReceiveTimestamp());
        }
        break;
      //采购退货单
      case 3:
        PurchaseReturnOrderRepository purRetOrderRead = (PurchaseReturnOrderRepository) SpringContextUtils.getBean(PurchaseReturnOrderRepository.class);
        PurchaseReturnOrder purRetOrder = purRetOrderRead.getById(sto.getOrderId());
        if (purRetOrder != null) {
          if (purRetOrder.getGeneratedState().equals(SaleOrderEnums.GeneratedState.LOGISTICS_WHOLE_GENERATE.getStatus())) {
            throw new BusinessException("退货单" + purRetOrder.getReturnCode() + "现有物流单已满足请货数量，无法再新建物流单！");
          }
          sto.setOrderCode(purRetOrder.getReturnCode());
          sto.setCustomerType(LogisticsBillEnums.CustomerType.UPSTREAM.getStatus());
          sto.setCustomerId(purRetOrder.getUpStreamCompanyId());
          sto.setDeliName(purRetOrder.getDeliName());
          sto.setDeliTel(purRetOrder.getDeliTel());
          sto.setDeliAreaCode(purRetOrder.getDeliAreaCode());
          sto.setDeliArea(purRetOrder.getDeliArea());
          sto.setDeliAddress(purRetOrder.getDeliAddress());
        }
        break;
      default:
        break;
    }
    ValidationUtils.validate(sto);
    switch (sto.getDeliveryType().intValue()) {
      //1.是物流发货时
      case 1:
        switch (sto.getLogisticsType().intValue()) {
          case 1:
            if (sto.getDriverContactPhone() == null || sto.getDriverName() == null || sto.getPlateNumber() == null) {
              throw new IllegalParameterException("选择陆运，货车车牌号、司机姓名、司机联系方式不能为空");
            }
            break;
          case 2:
            if (sto.getFlightNumber() == null) {
              throw new IllegalParameterException("选择空运，航班号不能为空");
            }
            break;
          case 3:
            if (sto.getShippingNumber() == null) {
              throw new IllegalParameterException("选择海运，航海号不能为空");
            }
            break;
          default:
            throw new IllegalParameterException("物流类型错误");
        }
        if (sto.getFreightTake().equals(LogisticsBillEnums.FreightTake.BUY.getStatus())) {
          if (sto.getFreightType() == null)
            throw new BusinessException("运费承担方式不能为空！");
        }
        break;
      //2.是快递发货时
      case 2:
        if (ExtStringUtils.isEmpty(sto.getCourierNumber())) {
          throw new BusinessException("快递单号不能为空！");
        }
        if(sto.getLogisticsType() != null){
          sto.setLogisticsType(null);
        }
        if (ExtStringUtils.isBlank(String.valueOf(sto.getFreightTake().intValue()))) {
          throw new BusinessException("运费承担方不能为空！");
        }
        if (sto.getFreightTake().equals(LogisticsBillEnums.FreightTake.BUY.getStatus())) {
          if (sto.getFreightType() == null)
            throw new BusinessException("运费承担方式不能为空！");
        }
        break;
      //3.是其它发货时
      case 3:
        if (sto.getDepotId() == null) {
          throw new BusinessException("出货仓库不能为空！");
        }
        if (sto.getLogisticsType() != null) {
          sto.setLogisticsType(null);
        }
        if (sto.getFreightTake().equals(LogisticsBillEnums.FreightTake.BUY.getStatus())) {
          if (sto.getFreightType() == null)
            throw new BusinessException("运费承担方式不能为空！");
        }
        break;
      default:
        throw new IllegalParameterException("发货类型错误");
    }
    ExtBeanUtils.copyProperties(sto, this);
    generatorCommonValue();
    //添加订单项
    ExtAssert.notNull(sto.getItems(), "物流单明细对象为空");
    this.items = new ArrayList<>();
    sto.getItems().stream()
            .filter(item -> item.getQuantity().compareTo(BigDecimal.ZERO) > 0 )
            .forEach(item -> {
      this.items.add(new LogisticsBillItem(item));
    });
  }

  /**
   * 新增物流副单
   *
   * @param upLogisticsBill
   */
  public LogisticsBill(UpLogisticsBill upLogisticsBill) {
    ExtAssert.notNull(upLogisticsBill, "对象为空");
    PurchaseOrderRepository purchaseOrderRead = (PurchaseOrderRepository) SpringContextUtils.getBean("purchaseOrderRepositoryImpl");
    PurchaseOrder purRetOrder = purchaseOrderRead.getById(upLogisticsBill.getOrderId());
    SaleOrderRepository saleOrderRepository = (SaleOrderRepository) SpringContextUtils.getBean("saleOrderRepositoryImpl");
    SaleOrder saleOrder = saleOrderRepository.getById(purRetOrder.getSalesOrderId());
    ExtBeanUtils.copyProperties(upLogisticsBill, this);
    this.id = null;
    this.subjectBillId = upLogisticsBill.getId();
    this.orderId = saleOrder.getId();
    this.orderType = LogisticsBillEnums.OrderType.SALE.getStatus();
    this.orderCode = saleOrder.getCode();
    this.customerType = LogisticsBillEnums.CustomerType.DOWNSTREAM.getStatus();
    this.customerId = saleOrder.getDownStreamCompanyId();
    //直采直销默认为卖家承担运费
    this.freightTake = LogisticsBillEnums.FreightTake.SALE.getStatus();
    this.freightType = null;
    generatorCommonValue();
    StorehouseReadRepository storehouseRepository = (StorehouseReadRepository) SpringContextUtils.getBean(StorehouseReadRepository.class);
    Wrapper we = Wrapper.build();
    we.append(Restrictions.eq("businessEntityId", this.getBusinessEntityId())).append(Restrictions.eq("isPerchaseToSale", Short.valueOf("1")));
    Storehouse storehouse = storehouseRepository.getOne(we);
    this.depotId = storehouse.getId();
    List<SaleOrderItem> saleOrderItems = saleOrderRepository.getItemsBySaleOrderId(saleOrder.getId());
    this.items = new ArrayList<>();
    upLogisticsBill.getItems().forEach(item -> {
      LogisticsBillItem billItem = new LogisticsBillItem();
      ExtBeanUtils.copyProperties(item, billItem);
      purRetOrder.getItems().forEach(purchaseOrderItem -> {
        if (purchaseOrderItem.getId().equals(billItem.getOrderItemId())) {
          billItem.setOrderItemId(purchaseOrderItem.getSaleOrderItemId());
        }
      });
      this.items.add(billItem);
    });
//    //TODO 当前订单项生成只支持一对一商品
//    this.items.forEach(item -> {
//      saleOrderItems.forEach(saleOrderItem -> {
//        if (saleOrderItem.getGoodsId().equals(item.getGoodsId())) {
//          item.setPrice(saleOrderItem.getPrice());
//          item.setOrderItemId(saleOrderItem.getId());
//          return;
//        }
//      });
//    });
  }

  /**
   * 修改物流单
   */
  public void modify(LogisticsBillMto mto) {
    ExtAssert.notNull(mto, "对象为空");
    if (this.subjectBillId != null) {
      throw new BusinessException("该物流单为直采直销的销售物流订单，请修改直采直销的采购物流订单");
    }
    ValidationUtils.validate(mto);
    if (!this.getLogisticsState().equals(LogisticsBillEnums.State.UNDELIVERY.getStatus())) {
      throw new BusinessException("订单不是未发货状态，不能修改");
    }
    this.lastUpdateTimeStamp = System.currentTimeMillis();
    ExtBeanUtils.copyProperties(mto, this);
//    mto.getItems().forEach(logisticsBillItemMto -> {
//      this.items.add(new LogisticsBillItem(logisticsBillItemMto));
//    });
//
  }

  /**
   * 修改物流副单
   */
  public void modifySecondaryBill(UpLogisticsBill upLogisticsBill) {
    SaleOrderRepository saleOrderRepository = (SaleOrderRepository) SpringContextUtils.getBean("saleOrderRepositoryImpl");
    SaleOrder saleOrder = saleOrderRepository.getById(this.getOrderId());
    this.logisticsCompanyId = upLogisticsBill.getLogisticsCompanyId();
    this.logisticsType = upLogisticsBill.getLogisticsType();
    this.plateNumber = upLogisticsBill.getPlateNumber();
    this.driverName = upLogisticsBill.getDriverName();
    this.driverContactPhone = upLogisticsBill.getDriverContactPhone();
    this.flightNumber = upLogisticsBill.getFlightNumber();
    this.shippingNumber = upLogisticsBill.getShippingNumber();
    this.etaDateTimestamp = upLogisticsBill.getEtaDateTimestamp();
    this.receiveTimestamp = upLogisticsBill.getReceiveTimestamp();
    this.deliArea = upLogisticsBill.getDeliArea();
    this.deliAddress = upLogisticsBill.getDeliAddress();
    this.deliAreaCode = upLogisticsBill.getDeliAreaCode();
    this.deliName = upLogisticsBill.getDeliName();
    this.deliTel = upLogisticsBill.getDeliTel();
    this.deliveryDeliArea = upLogisticsBill.getDeliveryDeliArea();
    this.deliveryDeliAddress = upLogisticsBill.getDeliveryDeliAddress();
    this.deliveryDeliAreaCode = upLogisticsBill.getDeliveryDeliAreaCode();
    this.deliveryNotes = upLogisticsBill.getDeliveryNotes();
    this.totalFreight = upLogisticsBill.getTotalFreight();
    //直采直销销售物流单默认为卖家承担运费
    this.freightTake = LogisticsBillEnums.FreightTake.SALE.getStatus();
    LogisticsBillRepository logisticsBillRepository = (LogisticsBillRepository) SpringContextUtils.getBean(LogisticsBillRepository.class);
    this.items = logisticsBillRepository.getItemsByLogisticsBillId(this.id);

    //TODO 当前订单项生成只支持一对一商品
    this.items.forEach(item -> {
      upLogisticsBill.getItems().forEach(upLogisticsBillItem -> {
        if (upLogisticsBillItem.getGoodsId().equals(item.getGoodsId())) {
          item.setQuantity(upLogisticsBillItem.getQuantity());
          return;
        }
      });
    });

  }

  private void generatorCommonValue() {
    this.code = CodeGenerateUtil.codeGenerate(CodeExpEnum.LOGISTICS_BILL_CODE_EXP.getCodeExp(), this.orderId);
    this.logisticsState = LogisticsBillEnums.State.UNDELIVERY.getStatus();
    this.statementState = LogisticsBillEnums.Statement.NOT_STATEMENT.getStatus();
    initDefault();
  }

  /**
   * 生成对账单
   */
  public void generating(Long statementOfAccountId) {
    if (this.statementState.equals(LogisticsBillEnums.Statement.STATEMENT.getStatus())) {
      throw new BusinessException("物流单" + this.code + "已生成对账单!");
    }
    this.statementId = statementOfAccountId;
    this.statementState = LogisticsBillEnums.Statement.STATEMENT.getStatus();
  }

  /**
   * 取消对账单
   */
  public void cancelGenerating() {
    if (!this.statementState.equals(LogisticsBillEnums.Statement.STATEMENT.getStatus())) {
      throw new BusinessException("物流单" + this.code + "未生成对账单!");
    }
    this.statementId = null;
    this.statementState = LogisticsBillEnums.Statement.NOT_STATEMENT.getStatus();
  }

  /**
   * 发货
   * @param deliveryTimestamp 发货时间
   */
  public void delivery(Long deliveryTimestamp) {
    if (this.orderType.equals(LogisticsBillEnums.OrderType.PURCHASE.getStatus()) ||
            this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_SALE.getStatus())) {
      throw new BusinessException("非我方发货物流单，发货失败！");
    }
    if (this.logisticsState == null || !this.logisticsState.equals(LogisticsBillEnums.State.UNDELIVERY.getStatus())) {
      throw new BusinessException("物流单据状态不是未发车，确认发货失败！");
    }
    //直采直销发货先判断主物流单是否已发货
    if (this.isPurchaseSaleLogisticsBill()) {
      LogisticsBillReadRepository logisticsBillReadRepository = (LogisticsBillReadRepository) SpringContextUtils.getBean(LogisticsBillRepository.class);
      LogisticsBill subjectBill = logisticsBillReadRepository.getById(this.subjectBillId);
      //如果不是已发车 不允许发车
      if (!subjectBill.getLogisticsState().equals(LogisticsBillEnums.State.DELIVEED.getStatus())) {
        throw new BusinessException("直采直销的采购物流未发货，确认发货失败！");
      }
    }

    this.juStatement(0);

    this.logisticsState = LogisticsBillEnums.State.DELIVEED.getStatus();
    this.deliveryTimestamp = deliveryTimestamp == null ? System.currentTimeMillis() : deliveryTimestamp;
  }

  /**
   * 直采直销关联物流单发货
   */
  public void deliverySecondaryBill() {
    if (this.logisticsState == null || !this.logisticsState.equals(LogisticsBillEnums.State.UNDELIVERY.getStatus())) {
      throw new BusinessException("物流单据状态不是未发车，确认发货失败！");
    }
    this.logisticsState = LogisticsBillEnums.State.DELIVEED.getStatus();
    this.deliveryTimestamp = System.currentTimeMillis();
  }

  /**
   * 直接收货
   */
  public void collect(Long storageTimestamp) {
    if (this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_PURCHASE.getStatus()) ||
            this.orderType.equals(LogisticsBillEnums.OrderType.SALE.getStatus())) {
      throw new BusinessException("无法代签收，确认收货失败！");
    }
    if (this.logisticsState == null || !this.logisticsState.equals(LogisticsBillEnums.State.DELIVEED.getStatus()))
      throw new BusinessException("物流单据状态不是已发车，确认收货失败！");
    this.juStatement(1);

    this.logisticsState = LogisticsBillEnums.State.SIGNIN.getStatus();
    this.storageTimestamp = storageTimestamp == null ? System.currentTimeMillis() : storageTimestamp;
    if (this.storageTimestamp < this.deliveryTimestamp) {
      throw new BusinessException("签收时间不能早于发货时间");
    }
  }

  /**
   * 设置收货仓库后收货
   * @param depotId 收货仓库
   */
  public void collectDepot(Long depotId,Long storageTimestamp) {
    if (this.isPurchaseSaleLogisticsBill()) {
      throw new BusinessException("直采直销的物流单需在采购端收货！");
    }
    if ((this.orderType.equals(LogisticsBillEnums.OrderType.PURCHASE.getStatus())
            || this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_SALE.getStatus()))
            && depotId != null) {

      StorehouseReadRepository storehouseReadRepository = (StorehouseReadRepository) SpringContextUtils.getBean(StorehouseReadRepository.class);
      Storehouse storehouse = storehouseReadRepository.getById(depotId);
      if (storehouse == null)
        throw new BusinessException("仓库不存在，请检查！");
      this.depotId = depotId;
    }
    this.collect(storageTimestamp);
  }

  /**
   * 取消发货
   */
  public void cancel() {
    if (this.orderType.equals(LogisticsBillEnums.OrderType.PURCHASE.getStatus()) ||
            this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_SALE.getStatus())) {
      throw new BusinessException("非我方发货物流单，取消发货失败！");
    }
    if (this.logisticsState != null &&
            !this.logisticsState.equals(LogisticsBillEnums.State.DELIVEED.getStatus()))
      throw new BusinessException("物流单据状态不是已发车状态，取消发货失败！");
    if (this.isPurchaseSaleLogisticsBill()) {
      throw new BusinessException("直采直销的物流单需在供应端取消发货！");
    }
    this.juStatement(0);

    this.logisticsState = LogisticsBillEnums.State.UNDELIVERY.getStatus();
    this.deliveryTimestamp = null;
  }

  /**
   * 取消直采直销关联物流单发货
   */
  public void cancelSecondaryBill() {
    if (this.orderType.equals(LogisticsBillEnums.OrderType.PURCHASE.getStatus()) ||
            this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_SALE.getStatus())) {
      throw new BusinessException("非我方发货物流单，取消发货失败！");
    }
    if (this.logisticsState != null &&
            !this.logisticsState.equals(LogisticsBillEnums.State.DELIVEED.getStatus()))
      throw new BusinessException("物流单据状态不是已发车状态，取消发货失败！");
    this.juStatement(0);

    this.logisticsState = LogisticsBillEnums.State.UNDELIVERY.getStatus();
    this.deliveryTimestamp = null;
  }

  /**
   * 取消收货
   */
  public void cancelReceipt() {
    if (this.orderType.equals(LogisticsBillEnums.OrderType.SALE.getStatus()) ||
            this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_PURCHASE.getStatus())) {
      throw new BusinessException("非我方收货物流单，取消签收失败！");
    }
    if (this.isPurchaseSaleLogisticsBill()) {
      throw new BusinessException("直采直销的物流单需在采购端取消签收！");
    }
    if (this.logisticsState != null &&
            !this.logisticsState.equals(LogisticsBillEnums.State.SIGNIN.getStatus()))
      throw new BusinessException("物流单据状态不是已签收状态，取消签收失败！");
    this.juStatement(1);

    this.logisticsState = LogisticsBillEnums.State.DELIVEED.getStatus();
    this.storageTimestamp = null;
  }

  /**
   * 取消直采直销关联物流单签收
   */
  public void cancelReceiptSubjectBill() {
    if (this.orderType.equals(LogisticsBillEnums.OrderType.SALE.getStatus()) ||
            this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_PURCHASE.getStatus())) {
      throw new BusinessException("非我方收货物流单，取消签收失败！");
    }
    if (this.logisticsState != null &&
            !this.logisticsState.equals(LogisticsBillEnums.State.SIGNIN.getStatus()))
      throw new BusinessException("物流单据状态不是已签收状态，取消签收失败！");
    this.juStatement(1);

    this.logisticsState = LogisticsBillEnums.State.DELIVEED.getStatus();
    this.storageTimestamp = null;
  }

  /**
   * 删除
   */
  public void remove() {
    if (this.orderType.equals(LogisticsBillEnums.OrderType.PURCHASE.getStatus()) ||
            this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_SALE.getStatus())) {
      throw new BusinessException("非我方发货物流单，删除失败！");
    }
    if (this.isPurchaseSaleLogisticsBill()) {
      throw new BusinessException("直采直销的物流单需在供应端删除！");
    }
    if (this.logisticsState != null &&
            !this.logisticsState.equals(LogisticsBillEnums.State.UNDELIVERY.getStatus()))
      throw new BusinessException("物流单据状态不是未发车状态，删除失败！");

  }

  /**
   * 删除直采直销关联物流单
   */
  public void removeSenondaryBill() {
    if (this.orderType.equals(LogisticsBillEnums.OrderType.PURCHASE.getStatus()) ||
            this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_SALE.getStatus())) {
      throw new BusinessException("非我方发货物流单，删除失败！");
    }
    if (this.logisticsState != null &&
            !this.logisticsState.equals(LogisticsBillEnums.State.UNDELIVERY.getStatus()))
      throw new BusinessException("物流单据状态不是未发车状态，删除失败！");

  }

  /**
   * 直采直销修改运费承担方
   * @param type 运费承担方式  1、卖家承担 2、预收买家 3、买家到付
   */
  public void changeFreightType(Short type) {
    if (this.subjectBillId == null) {
      throw new BusinessException("不是直采直销单，不能修改运费承担方式");
    }
    if (!this.logisticsState.equals(LogisticsBillEnums.State.UNDELIVERY.getStatus())) {
      throw new BusinessException("物流已发车，不能修改运费承担方式");
    }
    switch (type) {
      case 1:
        this.freightTake = LogisticsBillEnums.FreightTake.SALE.getStatus();
        this.freightType = null;
        break;
      case 2:
        this.freightTake = LogisticsBillEnums.FreightTake.BUY.getStatus();
        this.freightType = LogisticsBillEnums.FreightType.BEFORE.getStatus();
        break;
      case 3:
        this.freightTake = LogisticsBillEnums.FreightTake.BUY.getStatus();
        this.freightType = LogisticsBillEnums.FreightType.AFTER.getStatus();
        break;
      default:
        throw new BusinessException("承担方式选择有误！");
    }

  }

  /**
   * 判断订单是否已生成对账单
   *
   * @param type
   */
  private void juStatement(int type) {
    //0发货 1收货
    switch (type) {
      case 0:
        if (this.orderType.equals(LogisticsBillEnums.OrderType.SALE.getStatus())) {
          SaleOrderReadRepository saleOrderReadRepository = (SaleOrderReadRepository) SpringContextUtils.getBean("saleOrderRepositoryImpl");
          SaleOrder saleOrder = saleOrderReadRepository.getById(this.orderId);
          if (saleOrder.getOrdState().equals(SaleOrderEnums.State.STATEMENT.getStatus())) {
            throw new BusinessException("销售单" + saleOrder.getCode() + "已生成对账单，无法再修改相关信息！");
          }
        }
        if (this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_PURCHASE.getStatus())) {
          PurchaseReturnOrderRepository purchaseReturnOrderRepository = (PurchaseReturnOrderRepository) SpringContextUtils.getBean(PurchaseReturnOrderRepository.class);
          PurchaseReturnOrder purchaseReturnOrder = purchaseReturnOrderRepository.getById(this.orderId);
          if (purchaseReturnOrder.getReturnOrdState().equals(PurchaseReturnOrderEnums.OrdState.STATEMENT.getStatus())) {
            throw new BusinessException("采购退货单" + purchaseReturnOrder.getReturnCode() + "已生成对账单，无法再修改相关信息！");
          }
        }
        break;
      case 1:
        if (this.orderType.equals(LogisticsBillEnums.OrderType.PURCHASE.getStatus())) {
          PurchaseOrderReadRepository purchaseOrderReadRepository = (PurchaseOrderReadRepository) SpringContextUtils.getBean("purchaseOrderRepositoryImpl");
          PurchaseOrder purchaseOrder = purchaseOrderReadRepository.getById(this.orderId);
          if (purchaseOrder.getOrdState().equals(PurchaseOrderEnums.OrdState.STATEMENT.getStatus())) {
            //TODO 特殊情况 如果是直采直销单一方已对账一方未对账 报错显示业务冲突
            if (purchaseOrder.getOrderType().equals(PurchaseOrderEnums.OrderType.DIRECT_PURCHASE_AND_SALE.getStatus())) {
              throw new BusinessException("业务冲突，请联系客服！");
            }
            throw new BusinessException("采购单" + purchaseOrder.getCode() + "已生成对账单，无法再修改相关信息！");
          }
        }
        if (this.orderType.equals(LogisticsBillEnums.OrderType.RETURN_SALE.getStatus())) {
          SaleReturnOrderReadRepository saleReturnOrderReadRepository = (SaleReturnOrderReadRepository) SpringContextUtils.getBean(SaleReturnOrderReadRepository.class);
          SaleReturnOrder saleReturnOrder = saleReturnOrderReadRepository.getById(this.orderId);
          if (saleReturnOrder.getReturnOrdState().equals(SaleReturnOrderEnums.State.STATEMENT.getStatus())) {
            throw new BusinessException("销售退货单" + saleReturnOrder.getCode() + "已生成对账单，无法再修改相关信息！");
          }
        }
        break;
    }
  }

  private boolean isPurchaseSaleLogisticsBill() {
    if (this.orderType.equals(LogisticsBillEnums.OrderType.SALE.getStatus()) && this.subjectBillId != null) {
      return true;
    }
    if (this.orderType.equals(LogisticsBillEnums.OrderType.PURCHASE.getStatus())) {
      PurchaseOrderReadRepository purchaseOrderReadRepository = (PurchaseOrderReadRepository) SpringContextUtils.getBean("purchaseOrderRepositoryImpl");
      PurchaseOrder purchaseOrder = purchaseOrderReadRepository.getById(this.orderId);
      if (purchaseOrder.getOrderType().equals(PurchaseOrderEnums.OrderType.DIRECT_PURCHASE_AND_SALE.getStatus())) {
        return true;
      }
    }
    return false;
  }
}
